/**
 * Created by Admin on 05.01.2015.
 */

(function ($) {

    var SceneObject = $.inherit({

        addBuffers: function (bufferData) {
            var sceneObject = this;
            var gl = this.gl;
            $.each(bufferData, function (bufferName, data) {
                sceneObject._buffers[bufferName] = new GlBuffer(gl,
                    data.array || [],
                    data.itemSize,
                    data.numItems,
                    data.dataType || Float32Array,
                    data.bufferType || gl.ARRAY_BUFFER)
            });
            return this;
        },

        __constructor: function (gl, bufferData) {
            this._buffers = {};
            this.gl = gl;
            this.pMatrix = mat4.create();

            this.addBuffers(bufferData);
        },

        destroyStrategy: $.noop,

        _destroy: function () {
            $.each(this._buffers, function (_, buffer) {
                buffer._destroy();
            });
            this.destroyStrategy();
        }


    });

    var BaseSceneObject = $.inherit(SceneObject, {
        pMatrix: null,
        camera: null,
        currentAngle: 0,
        lastTime: 0,

        __constructor: function (gl, vertices, indices) {
            this.__base(gl, {

                vertexPositionBuffer: {
                    array: vertices,
                    itemSize: 3,
                    numItems: vertices.length / 3
                },

                vertexIndexBuffer: {
                    array: indices,
                    itemSize: 1,
                    numItems: indices.length,
                    dataType: Uint16Array,
                    bufferType: gl.ELEMENT_ARRAY_BUFFER
                }

            });
            this.currentAngle = 0;
            this.lastTime = 0;
        },

        _animate: function () {
            var timeNow = new Date().getTime();
            var lastTime = this.lastTime;
            if (lastTime != 0) {
                var elapsed = timeNow - lastTime;
                this.currentAngle += (90 * elapsed) / 1000.0;
            }
            this.lastTime = timeNow;
        },

        setCamera: function (camera) {
            this.camera = camera;
        },

        animate: function () {
            var gl = this.gl;
            mat4.perspective(100, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, this.pMatrix);
            this.camera.updateMovementMatrix();
        },

        bindAttributes: function (attributes) {
            var gl = this.gl;
            var buffer = this._buffers.vertexPositionBuffer;
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
            var ATTRIBUTES = GlColoredSceneObject.ATTRIBUTES;
            gl.vertexAttribPointer(attributes[ATTRIBUTES.VERTEX_POSITION], buffer.itemSize, gl.FLOAT, false, 0, 0);
            this.bindAttributesStrategy(attributes);
        },

        bindAttributesStrategy: $.noop,

        _setMatrixUniforms: function (uniforms) {
            var gl = this.gl;
            var UNIFORMS = GlColoredSceneObject.UNIFORMS;
            gl.uniformMatrix4fv(uniforms[UNIFORMS.MV_MATRIX], false, this.camera.getMovementMatrix());
            gl.uniformMatrix4fv(uniforms[UNIFORMS.P_MATRIX], false, this.pMatrix);
        },

        setUniforms: function (uniforms) {
            this._setMatrixUniforms(uniforms);
            this.setUniformsStrategy(uniforms)
        },

        setUniformsStrategy: $.noop,

        render: function () {
            var gl = this.gl;
            var vertexIndexBuffer = this._buffers.vertexIndexBuffer;
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer.buffer);
            gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
        }

    }, {});

    var ClickableObject = $.inherit(BaseSceneObject, {

        __constructor: function (gl, vertices, indices) {
            this.__base(gl, vertices, indices);
            this.rgba = [0, 0, 0, 0];
            this.isClick = false;
            this.handlers = {};
        },

        setCamera: function (camera) {
            this.camera = camera;
        },

        animate: function () {
            var gl = this.gl;
            mat4.perspective(100, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, this.pMatrix);
            this.camera.updateMovementMatrix();
        },

        setUniformsStrategy: function (uniforms) {
            var gl = this.gl;
            gl.uniform4f(uniforms["clickRgba"], this.rgba[0], this.rgba[1], this.rgba[2], this.rgba[3]);
            gl.uniform1f(uniforms["click"], this.isClick ? 1 : -1);

        },

        bind: function (event, handler) {
            if (!this.handlers[event]) this.handlers[event] = [];
            this.handlers[event].push(handler);
            return this;
        },

        unBind: function (event, handler) {
            var index;
            (index = this.handlers[event].indexOf(handler)) != -1 && this.handlers[event].splice(index, 1);
            return this;

        }

    }, {});

    window.GlColoredSceneObject = $.inherit(ClickableObject, {
        vertexColorBuffer: {},

        __constructor: function (gl, vertices, colors, indices) {
            this.__base(gl, vertices, indices);
            this.addBuffers({
                vertexColorBuffer: {
                    array: colors,
                    itemSize: 4,
                    numItems: colors.length / 4
                }
            });
        },

        bindAttributesStrategy: function (attributes) {
            var buffer = this._buffers.vertexColorBuffer;
            var gl = this.gl;
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer.buffer);
            gl.vertexAttribPointer(attributes[GlColoredSceneObject.ATTRIBUTES.VERTEX_COLOR], buffer.itemSize, gl.FLOAT, false, 0, 0);
        }

    }, {
        ATTRIBUTES: {
            VERTEX_POSITION: "aVertexPosition",
            VERTEX_COLOR: "aVertexColor"
        },

        UNIFORMS: {
            MV_MATRIX: "uMVMatrix",
            P_MATRIX: "uPMatrix"
        }
    });


})(window["jQuery"]);
